// OpAnnotationDwgRect.ts

import {
  Vector3,
  Font,
  Scene,
  Shape,
  ShapeGeometry,
  Mesh,
  Path,
  Vector2,
} from "../../WebViewer/THREE/Three";
import { AnnotationMesh, OpAnnotationDwg } from "./OpAnnotationDwg";

class OpAnnotationDwgRect extends OpAnnotationDwg {
  constructor(app: any) {
    super(app);
  }

  tempAnnotationPointerUp() {
    if (!this.tempAnnotation) return;
    const length = this.tempAnnotation.ptsArr.length - 1;
    let start = this.tempAnnotation.ptsArr[length - 1].clone();
    let end = this.tempAnnotation.ptsArr[length].clone();
    let distance = start.distanceTo(end);
    if (distance === 0) return;

    super.stopAnnotation();
  }

  createNewAnnotation(point: Vector3) {
    const scene = this.app.bimViewer.getIncrementalScene();
    const font = this.app.bimViewer.getRenderContext().getWebGLFont();
    const mesh = new AnnotationRectMesh({
      start: point,
      end: point,
      font,
      scene,
      lineSize: this.lineSize,
      textSize: this.textSize,
      color: this.color,
    });
    return mesh;
  }

  createAnnotationFromData(data: {
    ptsArr: Array<number[]>;
    lineSize: number;
    textSize: number;
    color: string;
  }) {
    let pointArr: Vector3[] = [];
    data.ptsArr.forEach((item: number[]) => {
      const v3 = new Vector3().fromArray(item);
      pointArr.push(v3);
    });

    const scene = this.app.bimViewer.getIncrementalScene();
    const font = this.app.bimViewer.getRenderContext().getWebGLFont();
    const mesh = new AnnotationRectMesh({
      start: pointArr[0],
      end: pointArr[1],
      font,
      scene,
      lineSize: data.lineSize,
      textSize: data.textSize,
      color: data.color,
    });

    const pixelScale2d = this.app.bimViewer.mainCamera.getPixelScale2d();
    mesh.updateLineTextShape(pixelScale2d);

    mesh.setDragHandleVisible(false);

    return mesh;
  }
}

class AnnotationRectMesh extends AnnotationMesh {
  constructor(param: {
    start: Vector3;
    end: Vector3;
    font: Font;
    scene: Scene;
    lineSize: number;
    textSize: number;
    color: string;
  }) {
    super(param);

    this._createLineTextShape();
  }

  private _createLineTextShape() {
    const shape = new Shape();
    const shapeGeo = new ShapeGeometry(shape);
    this.lineShape = new Mesh(shapeGeo, this.material);
    this.scene.add(this.lineShape);

    this.ptsArr.forEach((point) => {
      const drag = this.createDragHandle(point);
      this.dragHandleArr.push(drag);
      drag.install(this.scene);
    });
  }

  updateLineTextShape(pixelScale2d: number) {
    pixelScale2d = pixelScale2d * (this.lineSize + 1);
    if (pixelScale2d < 0.00099) pixelScale2d = 0.00099;

    const startP = new Vector2(
      Math.min(this.ptsArr[0].x, this.ptsArr[1].x),
      Math.max(this.ptsArr[0].y, this.ptsArr[1].y)
    );
    const endP = new Vector2(
      Math.max(this.ptsArr[0].x, this.ptsArr[1].x),
      Math.min(this.ptsArr[0].y, this.ptsArr[1].y)
    );

    const shape = new Shape();
    shape.moveTo(startP.x, startP.y);
    shape.lineTo(endP.x, startP.y);
    shape.lineTo(endP.x, endP.y);
    shape.lineTo(startP.x, endP.y);
    shape.closePath();

    const holePath = new Path();
    holePath.moveTo(startP.x + pixelScale2d, startP.y - pixelScale2d);
    holePath.lineTo(endP.x - pixelScale2d, startP.y - pixelScale2d);
    holePath.lineTo(endP.x - pixelScale2d, endP.y + pixelScale2d);
    holePath.lineTo(startP.x + pixelScale2d, endP.y + pixelScale2d);
    holePath.closePath();

    shape.holes.push(holePath);

    const shapeGeo = new ShapeGeometry(shape);
    this.lineShape.geometry.dispose();
    this.lineShape.geometry = shapeGeo;
  }
}

export { OpAnnotationDwgRect };
